#include "atlbase.h"
#include "WPDevice.h"
#include "stdafx.h"
#include <vcclr.h>
#include "WPDException.h"
#include "PortableDevice.h"
#include "PortableDeviceApi.h"

#define NUM_OBJECTS_TO_REQUEST  10

WPDevice::WPDevice()
{
}

WPDevice::~WPDevice()
{

}


DeviceContent^ WPDevice::enumerateContent()
{	
	//connect();
	//recusrsiveEnumeration(gcnew String(WPD_DEVICE_OBJECT_ID),);
	return m_Content;
}

void* WPDevice::getClientInfo()
{
	return NULL;
}

/*void* WPDevice::connect()
{
	HRESULT                         hr              = S_OK;
	UINT                            uiCurrentDevice = 0;
	CHAR                            szSelection[81] = {0};
	DWORD                           cPnPDeviceIDs   = 0;
	LPWSTR*                         pPnpDeviceIDs   = NULL;

	CComPtr<IPortableDeviceManager> pPortableDeviceManager;
	CComPtr<IPortableDeviceValues>  pClientInformation;


	IPortableDevice* pDevice;

	// Fill out information about your application, so the device knows
	// who they are speaking to.

	//getClientInfo(&pClientInformation);

	// Enumerate and display all devices.
	//cPnPDeviceIDs = EnumerateAllDevices();

	if (cPnPDeviceIDs > 0)
	{
		// Prompt user to enter an index for the device they want to choose.
		printf("Enter the index of the device you wish to use.\n>");
		//hr = StringCbGetsA(szSelection,sizeof(szSelection));
		if (SUCCEEDED(hr))
		{
			uiCurrentDevice = (UINT) atoi(szSelection);
			if (uiCurrentDevice >= cPnPDeviceIDs)
			{
				printf("An invalid device index was specified, defaulting to the first device in the list.\n");
				uiCurrentDevice = 0;
			}
		}
		else
		{
			printf("An invalid device index was specified, defaulting to the first device in the list.\n");
			uiCurrentDevice = 0;
		}

		// CoCreate the IPortableDeviceManager interface to enumerate
		// portable devices and to get information about them.
		hr = CoCreateInstance(CLSID_PortableDeviceManager,
			NULL,
			CLSCTX_INPROC_SERVER,
			IID_IPortableDeviceManager,
			(VOID**) &pPortableDeviceManager);
		if (FAILED(hr))
		{
			printf("! Failed to CoCreateInstance CLSID_PortableDeviceManager, hr = 0x%lx\n",hr);
		}

		// Allocate an array to hold the PnPDeviceID strings returned from
		// the IPortableDeviceManager::GetDevices method
		if (SUCCEEDED(hr) && (cPnPDeviceIDs > 0))
		{
			pPnpDeviceIDs = new LPWSTR[cPnPDeviceIDs];
			if (pPnpDeviceIDs != NULL)
			{
				DWORD dwIndex = 0;

				hr = pPortableDeviceManager->GetDevices(pPnpDeviceIDs, &cPnPDeviceIDs);
				if (SUCCEEDED(hr))
				{
					// CoCreate the IPortableDevice interface and call Open() with
					// the chosen PnPDeviceID string.
					hr = CoCreateInstance(CLSID_PortableDevice,
						NULL,
						CLSCTX_INPROC_SERVER,
						IID_IPortableDevice,
						(VOID**) ppDevice);
					if (SUCCEEDED(hr))
					{
						if (ppDevice != NULL)
						{
							hr = (*ppDevice)->Open(pPnpDeviceIDs[uiCurrentDevice], pClientInformation);
							if (FAILED(hr))
							{
								if (hr == E_ACCESSDENIED)
								{
									printf("Failed to Open the device for Read Write access, will open it for Read-only access instead\n");
									pClientInformation->SetUnsignedIntegerValue(WPD_CLIENT_DESIRED_ACCESS, GENERIC_READ);
									hr = (*ppDevice)->Open(pPnpDeviceIDs[uiCurrentDevice], pClientInformation);
									if (FAILED(hr))
									{
										printf("! Failed to Open the device, hr = 0x%lx\n",hr);
										// Release the IPortableDevice interface, because we cannot proceed
										// with an unopen device.
										(*ppDevice)->Release();
										*ppDevice = NULL;
									}
								}
								else
								{
									printf("! Failed to Open the device, hr = 0x%lx\n",hr);
									// Release the IPortableDevice interface, because we cannot proceed
									// with an unopen device.
									(*ppDevice)->Release();
									*ppDevice = NULL;
								}
							}
						}
						else
						{
							hr = E_UNEXPECTED;
							printf("! Failed to Open the device because we were returned a NULL IPortableDevice interface pointer, hr = 0x%lx\n",hr);
						}
					}
					else
					{
						printf("! Failed to CoCreateInstance CLSID_PortableDevice, hr = 0x%lx\n",hr);
					}
				}
				else
				{
					printf("! Failed to get the device list from the system, hr = 0x%lx\n",hr);
				}

				// Free all returned PnPDeviceID strings by using CoTaskMemFree.
				// NOTE: CoTaskMemFree can handle NULL pointers, so no NULL
				//       check is needed.
				for (dwIndex = 0; dwIndex < cPnPDeviceIDs; dwIndex++)
				{
					CoTaskMemFree(pPnpDeviceIDs[dwIndex]);
					pPnpDeviceIDs[dwIndex] = NULL;
				}

				// Delete the array of LPWSTR pointers
				delete [] pPnpDeviceIDs;
				pPnpDeviceIDs = NULL;
			}
			else
			{
				printf("! Failed to allocate memory for LPWSTR array\n");
			}
		}

	}
}
*/
void  WPDevice::recusrsiveEnumeration(String ^objectID, void *portableContent)
{
	if ((objectID == nullptr) || (portableContent == nullptr))
	{
		return;
	}

	HRESULT                               hr = S_OK;
	CComPtr<IEnumPortableDeviceObjectIDs> pEnumObjectIDs;
	CComPtr<IPortableDeviceContent> pContent((IPortableDeviceContent*)portableContent);

	m_Content->add(gcnew ContentObject(/*objectID*/));
	pin_ptr<const __wchar_t> umstring = PtrToStringChars(objectID);
	
	// Get an IEnumPortableDeviceObjectIDs interface by calling EnumObjects with the
	// specified parent object identifier.
	hr = pContent->EnumObjects(0,               // Flags are unused
							   umstring,     // Starting from the passed in object
							   NULL,            // Filter is unused
							   &pEnumObjectIDs);
	if (SUCCEEDED(hr))
	{
		// Loop calling Next() while S_OK is being returned.
		while(hr == S_OK)
		{
			DWORD  cFetched = 0;
			LPWSTR szObjectIDArray[NUM_OBJECTS_TO_REQUEST] = {0};
			hr = pEnumObjectIDs->Next(NUM_OBJECTS_TO_REQUEST,   // Number of objects to request on each NEXT call
									  szObjectIDArray,          // Array of LPWSTR array which will be populated on each NEXT call
									   &cFetched);               // Number of objects written to the LPWSTR array
			if (SUCCEEDED(hr))
			{
				// Traverse the results of the Next() operation and recursively enumerate
				// Remember to free all returned object identifiers using CoTaskMemFree()
				for (DWORD dwIndex = 0; dwIndex < cFetched; dwIndex++)
				{
					recusrsiveEnumeration(gcnew String(szObjectIDArray[dwIndex]),(void *)pContent);

					// Free allocated LPWSTRs after the recursive enumeration call has completed.
					CoTaskMemFree(szObjectIDArray[dwIndex]);
					szObjectIDArray[dwIndex] = NULL;
				}
			}
		}
	} else
	{
		throw gcnew WPDException("Failed to get IEnumPortableDeviceObjectIDs from IPortableDeviceContent, hr = " + hr);
	}
}

void *WPDevice::connect()
{
	void *temp = NULL;
	return  temp;
}